import Foundation
import Darwin

class VideoDownloaderHelper {
    private let socketPath = "/tmp/video_downloader.sock"
    private var serverSocket: Int32 = -1
    private var isServerRunning = true
    
    // 配置管理器
    let configManager = ConfigManager()
    
    // 数据库管理器
    let dbManager = DatabaseManager()
    
    // 下载队列管理
    private let downloadQueue = DispatchQueue(label: "downloadQueue", qos: .background)
    private let semaphore: DispatchSemaphore
    private var activeDownloads: [String: String] = [:]  // taskId: url
    private var queuedDownloads: [String] = []  // 只存储任务ID (String类型)
    private let maxConcurrentDownloads: Int
    private let queueLock = NSLock()
    
    init() {
        // 从配置中获取最大并发数
        let config = configManager.getConfig()
        self.maxConcurrentDownloads = config.maxConcurrentDownloads
        self.semaphore = DispatchSemaphore(value: maxConcurrentDownloads)
        
        // 启动时恢复未完成的任务
        recoverPendingTasks()
    }
    
    // 恢复未完成的任务
    private func recoverPendingTasks() {
        // 将正在下载的任务重置为待处理状态
        let downloadingTasks = dbManager.getAllTasks(status: .downloading)
        for task in downloadingTasks {
            _ = dbManager.updateTaskStatus(id: task.id, status: .pending)
        }
        
        // 获取所有待处理的任务 (pending状态的任务需要移到队列中)
        let pendingTasks = dbManager.getAllTasks(status: .pending)
        let queuedTasks = dbManager.getAllTasks(status: .queued)
        
        queueLock.lock()
        // 将pending任务更新为queued状态并加入队列
        for task in pendingTasks {
            _ = dbManager.updateTaskStatus(id: task.id, status: .queued)
            queuedDownloads.append(task.id)
        }
        // 加入已经排队的任务
        queuedDownloads.append(contentsOf: queuedTasks.map { String($0.id) })
        queueLock.unlock()
        
        let totalRecovered = pendingTasks.count + queuedTasks.count
        if totalRecovered > 0 {
            print("📋 Recovered \(totalRecovered) pending tasks from database")
            processDownloadQueue()
        }
    }
    
    func startServer() {
        print("Video Downloader Helper started")
        print("Creating Unix socket at: \(socketPath)")
        
        // 创建 Unix Domain Socket
        serverSocket = socket(AF_UNIX, SOCK_STREAM, 0)
        guard serverSocket != -1 else {
            print("Failed to create socket: \(String(cString: strerror(errno)))")
            return
        }
        
        // 删除可能存在的旧 socket 文件
        unlink(socketPath)
        
        // 设置 socket 地址
        var serverAddr = sockaddr_un()
        serverAddr.sun_family = sa_family_t(AF_UNIX)
        
        let pathBytes = socketPath.utf8CString
        guard pathBytes.count <= MemoryLayout.size(ofValue: serverAddr.sun_path) else {
            print("Socket path too long")
            close(serverSocket)
            return
        }
        
        withUnsafeMutablePointer(to: &serverAddr.sun_path) { pathPtr in
            pathPtr.withMemoryRebound(to: CChar.self, capacity: pathBytes.count) { charPtr in
                _ = pathBytes.withUnsafeBufferPointer { buffer in
                    memcpy(charPtr, buffer.baseAddress, buffer.count)
                }
            }
        }
        
        // 绑定 socket
        let bindResult = withUnsafePointer(to: &serverAddr) { ptr in
            ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) { sockaddrPtr in
                bind(serverSocket, sockaddrPtr, socklen_t(MemoryLayout<sockaddr_un>.size))
            }
        }
        
        guard bindResult == 0 else {
            print("Failed to bind socket: \(String(cString: strerror(errno)))")
            close(serverSocket)
            return
        }
        
        // 监听连接
        guard listen(serverSocket, 5) == 0 else {
            print("Failed to listen on socket: \(String(cString: strerror(errno)))")
            close(serverSocket)
            return
        }
        
        print("Socket server listening on \(socketPath)")
        
        // 接受连接循环
        while isServerRunning {
            let clientSocket = accept(serverSocket, nil, nil)
            guard clientSocket != -1 else {
                if isServerRunning {  // 只在仍在运行时打印错误
                    print("Failed to accept connection: \(String(cString: strerror(errno)))")
                }
                continue
            }
            
            if !isServerRunning {
                close(clientSocket)
                break
            }
            
            print("Client connected")
            handleClient(clientSocket: clientSocket)
            close(clientSocket)
        }
        
        // 清理资源
        close(serverSocket)
        unlink(socketPath)
        print("✅ Server stopped and resources cleaned up")
    }
    
    func stopServer() {
        print("Stopping server...")
        isServerRunning = false
        
        // 关闭服务器socket以中断accept循环
        if serverSocket != -1 {
            close(serverSocket)
            unlink(socketPath)
        }
        
        // 退出程序
        exit(0)
    }
    
    private func handleClient(clientSocket: Int32) {
        let bufferSize = 1024
        var buffer = [UInt8](repeating: 0, count: bufferSize)
        
        let bytesRead = recv(clientSocket, &buffer, bufferSize - 1, 0)
        guard bytesRead > 0 else {
            print("Failed to read from client socket")
            return
        }
        
        buffer[bytesRead] = 0 // 确保字符串结束
        guard let receivedData = String(bytes: buffer[0..<bytesRead], encoding: .utf8) else {
            print("Failed to decode received data")
            return
        }
        
        let command = receivedData.trimmingCharacters(in: .whitespacesAndNewlines)
        if !command.isEmpty {
            var response = ""
            
            if command == "STATUS" {
                // 处理队列状态查询请求
                let status = getQueueStatus()
                let stats = dbManager.getTaskStats()
                response = "QUEUE: \(status.active) active, \(status.queued) queued | TOTAL: \(stats.values.reduce(0, +)) tasks"
                for (status, count) in stats {
                    response += " | \(status.rawValue.uppercased()): \(count)"
                }
                response += "\n"
                print("📊 Status requested - \(response.trimmingCharacters(in: .whitespacesAndNewlines))")
            } else if command.hasPrefix("TASK:") {
                // 处理任务详情查询请求 格式: TASK:123456789012
                let taskIdStr = String(command.dropFirst(5))
                if let task = dbManager.getTask(id: taskIdStr) {
                    let formatter = DateFormatter()
                    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
                    
                    response = "TASK \(task.id): \(task.status.rawValue.uppercased())\n"
                    response += "URL: \(task.url)\n"
                    response += "Created: \(formatter.string(from: task.createdAt))\n"
                    
                    if let error = task.error {
                        response += "Error: \(error)\n"
                    }
                    
                    if let filePath = task.filePath {
                        response += "File: \(filePath)\n"
                    }
                } else {
                    response = "ERROR: Task not found\n"
                }
                print("� Task \(taskIdStr) details requested")
            } else if command == "LIST" {
                // 处理任务列表查询请求
                let recentTasks = dbManager.getAllTasks(limit: 10)
                response = "RECENT TASKS (\(recentTasks.count)):\n"
                for task in recentTasks {
                    let statusEmoji = getStatusEmoji(task.status)
                    response += "\(statusEmoji) ID:\(task.id) [\(task.status.rawValue.uppercased())] \(task.url)\n"
                }
                print("📋 Task list requested")
            } else if command == "SHUTDOWN" {
                // 处理关闭服务器请求
                response = "OK: Server shutting down\n"
                print("🛑 Shutdown command received, stopping server...")
                
                // 发送响应
                _ = send(clientSocket, response, response.count, 0)
                
                // 优雅关闭服务器
                DispatchQueue.main.async {
                    self.stopServer()
                }
                return
            } else {
                // 处理下载请求
                if let taskId = addToDownloadQueue(url: command) {
                    print("Received download request for: \(command) (ID: \(taskId))")
                    response = "OK: Task added with ID \(taskId)\n"
                } else {
                    response = "ERROR: Failed to add task\n"
                }
            }
            
            // 发送响应
            _ = send(clientSocket, response, response.count, 0)
        }
    }
    
    func getStatusEmoji(_ status: TaskStatus) -> String {
        switch status {
        case .pending: return "⏸️"
        case .queued: return "⏳"
        case .downloading: return "⬇️"
        case .completed: return "✅"
        case .failed: return "❌"
        case .cancelled: return "🚫"
        }
    }
    
    private func addToDownloadQueue(url: String) -> String? {
        // 首先在数据库中创建任务
        guard let taskId = dbManager.addTask(url: url) else {
            print("❌ Failed to add task to database")
            return nil
        }
        
        queueLock.lock()
        defer { queueLock.unlock() }
        
        // 将任务状态从pending更新为queued
        _ = dbManager.updateTaskStatus(id: taskId, status: .queued)
        queuedDownloads.append(taskId)
        
        print("📥 Added to queue: \(url) (ID: \(taskId))")
        print("📊 Queue status: \(activeDownloads.count) active, \(queuedDownloads.count) queued")
        
        // 尝试启动下载
        processDownloadQueue()
        
        return taskId
    }
    
    private func processDownloadQueue() {
        downloadQueue.async {
            while true {
                self.queueLock.lock()
                
                // 检查是否有可用的下载槽位和队列中的任务
                guard self.activeDownloads.count < self.maxConcurrentDownloads && !self.queuedDownloads.isEmpty else {
                    self.queueLock.unlock()
                    break
                }
                
                // 取出队列中的第一个任务ID
                let taskId = self.queuedDownloads.removeFirst()
                
                // 从数据库获取任务详情
                guard let task = self.dbManager.getTask(id: taskId) else {
                    print("❌ Task \(taskId) not found in database")
                    self.queueLock.unlock()
                    continue
                }
                
                self.activeDownloads[taskId] = task.url
                
                print("🚀 Starting download: \(task.url) (ID: \(taskId))")
                print("📊 Queue status: \(self.activeDownloads.count) active, \(self.queuedDownloads.count) queued")
                
                self.queueLock.unlock()
                
                // 更新任务状态为正在下载
                _ = self.dbManager.updateTaskStatus(id: taskId, status: .downloading)
                
                // 在后台执行下载
                DispatchQueue.global(qos: .background).async {
                    let success = self.downloadVideo(url: task.url, downloadId: taskId)
                    
                    // 下载完成后（无论成功或失败），更新状态并减少活跃下载数
                    self.queueLock.lock()
                    self.activeDownloads.removeValue(forKey: taskId)
                    let statusEmoji = success ? "✅" : "❌"
                    let statusText = success ? "completed successfully" : "failed"
                    print("\(statusEmoji) Download \(statusText): \(task.url) (ID: \(taskId))")
                    print("📊 Queue status: \(self.activeDownloads.count) active, \(self.queuedDownloads.count) queued")
                    self.queueLock.unlock()
                    
                    // 注意：downloadVideo方法已经更新了数据库状态，包括文件路径
                    // 这里不再需要额外的updateTaskStatus调用
                    
                    // 递归处理队列中的下一个任务
                    self.processDownloadQueue()
                }
            }
        }
    }
    
    func getQueueStatus() -> (active: Int, queued: Int) {
        queueLock.lock()
        defer { queueLock.unlock() }
        return (active: activeDownloads.count, queued: queuedDownloads.count)
    }
    
    deinit {
        if serverSocket != -1 {
            close(serverSocket)
            unlink(socketPath)
        }
    }
    
    func downloadVideo(url: String, downloadId: String = "") -> Bool {
        let prefix = !downloadId.isEmpty ? "[ID:\(downloadId)]" : ""
        print("\(prefix) 🎬 Starting download for: \(url)")
        
        // 获取配置
        let config = configManager.getConfig()
        
        // 第一步：验证URL格式
        guard isValidURL(url) else {
            let errorMsg = "Invalid URL format"
            print("\(prefix) ❌ Error: \(errorMsg)")
            print("\(prefix) 💡 Please check the URL and try again")
            
            if !downloadId.isEmpty {
                _ = dbManager.updateTaskStatus(id: downloadId, status: .failed, errorMessage: errorMsg)
            }
            return false
        }
        
        // 检查配置的 yt-dlp 路径是否存在，如果不存在则尝试默认路径
        var ytDlpPath = config.ytDlpPath
        
        if !FileManager.default.fileExists(atPath: ytDlpPath) {
            print("\(prefix) ⚠️ Configured yt-dlp path not found: \(ytDlpPath)")
            print("\(prefix) 🔍 Searching for yt-dlp in standard locations...")
            
            let fallbackPaths = [
                "/opt/homebrew/bin/yt-dlp",
                "/usr/local/bin/yt-dlp",
                "/usr/bin/yt-dlp"
            ]
            
            var foundPath: String?
            for path in fallbackPaths {
                if FileManager.default.fileExists(atPath: path) {
                    foundPath = path
                    break
                }
            }
            
            guard let validPath = foundPath else {
                let errorMsg = "yt-dlp not found. Configured path: \(config.ytDlpPath)"
                print("\(prefix) ❌ Error: \(errorMsg)")
                print("\(prefix) 💡 Install yt-dlp with: brew install yt-dlp")
                print("\(prefix) 💡 Or update config at: ~/.vdh/config.yaml")
                
                if !downloadId.isEmpty {
                    _ = dbManager.updateTaskStatus(id: downloadId, status: .failed, errorMessage: errorMsg)
                }
                return false
            }
            
            ytDlpPath = validPath
            print("\(prefix) ✅ Found yt-dlp at: \(ytDlpPath)")
        }
        
        print("\(prefix) 🛠️ Using yt-dlp at: \(ytDlpPath)")
        
        let task = Process()
        task.launchPath = ytDlpPath
        
        // 创建下载目录
        let downloadsPath = config.outputDirectory
        try? FileManager.default.createDirectory(atPath: downloadsPath, withIntermediateDirectories: true)
        
        // 生成输出文件名模板
        let outputTemplate = "\(downloadsPath)/%(title)s.%(id)s.%(ext)s"
        
        // 构建基本参数
        var arguments = [
            "--cookies-from-browser", "chrome", 
            "--merge-output-format", "mp4",
            "--no-playlist",
        ]
        
        // 添加代理设置（如果配置了）
        if let proxyUrl = config.proxyUrl, !proxyUrl.isEmpty {
            arguments.append(contentsOf: ["--proxy", proxyUrl])
            print("\(prefix) 🌐 Using proxy: \(proxyUrl)")
        }
        
        // 添加URL和输出模板
        arguments.append(url)
        arguments.append(contentsOf: ["-o", outputTemplate])
        
        task.arguments = arguments
        
        print("\(prefix) 📝 Download command: \(ytDlpPath) \(arguments.joined(separator: " "))")
        print("\(prefix) 📁 Download directory: \(downloadsPath)")
        if config.enableLogging {
            print("\(prefix) 🔧 Config: proxy=\(config.proxyUrl ?? "none"), max_concurrent=\(config.maxConcurrentDownloads)")
        }
        
        let pipe = Pipe()
        task.standardOutput = pipe
        task.standardError = pipe
        
        var actualFilePath: String?
        
        do {
            try task.run()
            task.waitUntilExit()
            
            let data = pipe.fileHandleForReading.readDataToEndOfFile()
            if let output = String(data: data, encoding: .utf8) {
                print("\(prefix) 📄 yt-dlp output:")
                print(output)
                
                // 尝试从输出中提取实际文件路径
                // 查找类似 "Merging formats into 'filename.mp4'" 的行
                let lines = output.components(separatedBy: .newlines)
                
                for line in lines {
                    let trimmedLine = line.trimmingCharacters(in: .whitespacesAndNewlines)
                    
                    // 查找合并格式的信息
                    if trimmedLine.contains("Merging formats into") && trimmedLine.contains(".mp4") {
                        if let startQuote = trimmedLine.firstIndex(of: "\""),
                           let endQuote = trimmedLine.lastIndex(of: "\""),
                           startQuote < endQuote {
                            let filename = String(trimmedLine[trimmedLine.index(after: startQuote)..<endQuote])
                            actualFilePath = filename
                            print("\(prefix) 📁 Extracted file path from merge message: \(actualFilePath!)")
                            break
                        }
                    }
                    
                    // 或者查找下载完成的信息
                    if trimmedLine.contains("has already been downloaded") && trimmedLine.contains(".mp4") {
                        // 提取路径：格式为 "[download] /path/to/file.mp4 has already been downloaded"
                        if let downloadPrefix = trimmedLine.range(of: "[download] "),
                           let hasAlreadyPrefix = trimmedLine.range(of: " has already been downloaded") {
                            let pathStart = trimmedLine.index(downloadPrefix.upperBound, offsetBy: 0)
                            let pathEnd = trimmedLine.index(hasAlreadyPrefix.lowerBound, offsetBy: 0)
                            if pathStart < pathEnd {
                                let filename = String(trimmedLine[pathStart..<pathEnd])
                                actualFilePath = filename.trimmingCharacters(in: .whitespaces)
                                print("\(prefix) 📁 Extracted file path from already downloaded message: \(actualFilePath!)")
                                break
                            }
                        }
                    }
                }
            }
            
            if task.terminationStatus == 0 {
                print("\(prefix) ✅ Download completed successfully!")
                
                if !downloadId.isEmpty {
                    print("\(prefix) 💾 Updating database - downloadId: \(downloadId), actualFilePath: '\(actualFilePath ?? "nil")'")
                    _ = dbManager.updateTaskStatus(id: downloadId, status: .completed, filePath: actualFilePath)
                    print("\(prefix) ✅ Database update completed")
                }
                return true
            } else {
                let errorMsg = "Download failed with exit code: \(task.terminationStatus)"
                print("\(prefix) ❌ \(errorMsg)")
                
                if !downloadId.isEmpty {
                    _ = dbManager.updateTaskStatus(id: downloadId, status: .failed, errorMessage: errorMsg)
                }
                return false
            }
            
        } catch {
            let errorMsg = "Failed to execute yt-dlp: \(error)"
            print("\(prefix) ❌ \(errorMsg)")
            
            if !downloadId.isEmpty {
                _ = dbManager.updateTaskStatus(id: downloadId, status: .failed, errorMessage: errorMsg)
            }
            return false
        }
    }
    
    // URL格式验证
    private func isValidURL(_ string: String) -> Bool {
        guard let url = URL(string: string),
              let scheme = url.scheme?.lowercased() else {
            return false
        }
        return ["http", "https"].contains(scheme)
    }
}